package http

import (
	"context"
	"errors"
	"github.com/gin-gonic/gin"
	"net/http"
	"os"
	"os/signal"
	"starry_sky/api/router"
	"starry_sky/internal/middleware/http-middleware"
	"starry_sky/internal/tools/logger"
	"strconv"
	"syscall"
	"time"
)

const (
	MaxMultipartMemory100MB = 100 << 20
)

type Server struct {
	Port        int          `json:"port"`
	Engine      *gin.Engine  `json:"engine"`
	UseRecovery bool         `json:"useRecovery"`
	ServerMode  string       `json:"serverMode"`
	HttpServer  *http.Server `json:"server"`
}

// port 端口
// serverMode 服务模式
// useRecovery 是否使用恢复（拦截项目中panic保证项目运行）
// NewServer Start 启动服务
func NewServer(port int, serverMode string, useRecovery bool) *Server {
	engine := gin.New()

	// 设置logger
	engine.Use(gin.Logger())
	// 设置恢复
	if useRecovery {
		engine.Use(gin.Recovery())
	}
	// 设置cors
	engine.Use(http_middleware.Cors)
	//设置全部路由
	router.Register(engine)
	httpServer := &http.Server{
		Addr:    ":" + strconv.Itoa(port),
		Handler: engine,
	}
	return &Server{
		Port:        port,
		ServerMode:  serverMode,
		UseRecovery: useRecovery,
		HttpServer:  httpServer,
		Engine:      engine,
	}
}

// Start 方法启动 HTTP 服务并监听系统信号
// 它会启动一个新的 goroutine 来监听 HTTP 请求，并等待中断信号
func (s *Server) Start() {
	// 创建一个用于接收系统信号的 channel
	// 我们希望监听 SIGINT（Ctrl+C）和 SIGTERM（终止信号）这两种信号
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	// 启动 HTTP 服务的 goroutine
	// 在后台执行 ListenAndServe，开始监听端口并处理请求
	go func() {
		logger.SysInfoF("Starting server on port %d...", s.Port)
		if err := s.HttpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
			// 如果服务器无法启动或意外关闭，输出错误信息
			logger.SysErrorF("Server listen failed: %v\n", err)
		}
	}()

	// 等待系统信号。这里会阻塞，直到收到中断信号
	<-signalChan
	// 收到信号后，开始执行停止操作
	s.End()
}

// End 方法用于优雅地停止 HTTP 服务
// 它会在给定的超时时间内等待所有请求处理完毕并关闭服务
func (s *Server) End() {
	// 创建一个带有 5 秒超时的 context，用于控制优雅关闭的最大等待时间
	// 如果 5 秒内服务没有停止，将强制退出
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel() // 确保 cancel 函数在方法退出时被调用

	// 输出关闭服务的提示
	logger.SysInfoF("Shutting down server gracefully...")

	// 调用 http.Server 的 Shutdown 方法，优雅关闭服务器
	// 它会等待所有正在处理的请求完成后再关闭服务器
	if err := s.HttpServer.Shutdown(ctx); logger.HasError(err) {
		// 如果服务器关闭失败，打印错误信息
		logger.SysErrorF("Server shutdown failed: %v\n", err)
	} else {
		// 如果服务器成功关闭，打印成功信息
		logger.SysErrorF("Server exited gracefully")
	}
}
